{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true,
    "pycharm": {
     "is_executing": false
    }
   },
   "outputs": [],
   "source": [
    "from gs_quant.api.gs.users import GsUsersApi\n",
    "from gs_quant.api.gs.workspaces import GsWorkspacesMarketsApi as ws_api\n",
    "from gs_quant.session import Environment, GsSession\n",
    "from gs_quant.target.workspaces_markets import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "GsSession.use(Environment.PROD, client_id=None, client_secret=None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### Initializing your Workspace\n",
    "\n",
    "Determine the basics of your Workspace (i.e name, description and entitlements over who can view and edit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "name = 'Example Workspace'\n",
    "alias = 'example-workspace'  # This needs to be unique across all users as to not have conflicting URLs\n",
    "description = 'This workspace was created as an example.'\n",
    "user_id = GsUsersApi.get_my_guid()\n",
    "\n",
    "# Entitle everyone internal to view but only yourself to edit and change entitlements\n",
    "entitlements = Entitlements(view=(user_id,), edit=(user_id,), admin=(user_id,))\n",
    "\n",
    "components = []  # Empty list of components with some to be added below"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### Add Components\n",
    "\n",
    "Workspaces currently support many components such as Promo (text), Plots, DataGrids, and Commentary. See all available components\n",
    "[here](https://developer.gs.com/p/docs/services/data/workspaces-markets/#components).\n",
    "\n",
    "To create a component, create the parameters object for the component such as PromoComponentParameters, fill out the required and optional fields.\n",
    "\n",
    "Then add the component using these parameters. Let's start with a simple Promo Component."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "#### Add a Promo Component \n",
    "\n",
    "If you want to add simple text to a workspace, this can be done by adding a Promo Component, as seen below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "promo_params = PromoComponentParameters(height=52, body='Your text here!', transparent=False)\n",
    "components.append(WorkspaceComponent(id_='promo-1', type_=ComponentType.promo, parameters=promo_params))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### Create the Workspace\n",
    "\n",
    "Now you are ready to create your workspace. Let us put everything together."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "layout = 'r(c12($0))'\n",
    "parameters = WorkspaceParameters(layout=layout, components=components)\n",
    "workspace = Workspace(parameters=parameters, name=name, alias=alias, entitlements=entitlements, description=description)\n",
    "workspace = ws_api.create_workspace(workspace)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "The above snippet will create a workspace that is now viewable at the URL https://marquee.gs.com/s/markets/{alias}. \n",
    "Substitute {alias} with the alias you set. Remember to change the alias since the example one probably already exists.\n",
    "\n",
    "The layout string controls the layout of your components. In this case, a simple layout with a single component that spans a single row.\n",
    "Learn more about layouts [here](https://developer.gs.com/p/docs/services/data/workspaces-markets/#layouts). \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### Updating the Workspace with Additional Components\n",
    "\n",
    "Now let us create a Workspace with some plots and a commentary component."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "#### Add a plot \n",
    "\n",
    "Start by creating plots in PlotTool Pro [here](https://marquee.gs.com/s/plottool/new) \n",
    "\n",
    "After you have created your plot, grab the plot id from the browser.\n",
    "* For example, the id for [this plot](https://marquee.gs.com/s/plottool/CH5RJJ9APZMRQ7B7) is <b>CHYYNR2YSD8W21GA<b>\n",
    "    \n",
    "You want all the underlying components that have entitlements to have the same entitlements as the Workspace, so all components are visible on the Workspace for the intended audience."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# Create the plot component parameters, setting the height to the desired height in pixels. Also, other configurations can be set such as hiding the legend.\n",
    "plot_params = PlotComponentParameters(height=300, hideLegend=False)\n",
    "plot_id = 'CHYYNR2YSD8W21GA'  # example plot id\n",
    "\n",
    "# Add the plot component to the list of components\n",
    "components.append(WorkspaceComponent(id_=plot_id, type_=ComponentType.plot, parameters=plot_params))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "#### Add a commentary stream"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "channel_1 = 'EQUITIES MACRO'\n",
    "channel_2 = 'EQUITIES GS BASKETS'\n",
    "commentary_params = CommentaryComponentParameters(height=300, commentary_channels=(channel_1, channel_2))\n",
    "components.append(\n",
    "    WorkspaceComponent(id_='streaming-commentary-1', type_=ComponentType.commentary, parameters=commentary_params)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "### Update the Workspace"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "ename": "MqRequestError",
     "evalue": "context: POST https://marquee.web.gs.com/v1/workspaces/markets\nstatus: 400, message: <!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\"/>\n<title>Request Body Validation Error</title>\n<style>body { font-family: sans-serif; } footer { font-style: italic; }</style>\n</head>\n<body>\n<h1>400 Bad Request - Request Body Validation Error</h1>\n\r\n<h2>Problem Description</h2>\r\n<p>\r\n    The request did not match any of the requests defined for this endpoint.\r\n</p>\r\n<h2>Details</h2>\r\n\r\n    <h3>Request Definition 1</h3>\r\n    <p>The JSON object in the body does not conform to the schema</p>\r\n    <ul>\r\n        \r\n        <li>error: ECMA 262 regex &quot;^(?:\\w{1,256}:){0,10}[\\w.]{1,256}$$&quot; does not match input string &quot;insert your user id&quot;\n    level: &quot;error&quot;\n    schema: {&quot;loadingURI&quot;:&quot;definition:/Token#&quot;,&quot;pointer&quot;:&quot;&quot;}\n    instance: {&quot;pointer&quot;:&quot;/entitlements/admin/0&quot;}\n    domain: &quot;validation&quot;\n    keyword: &quot;pattern&quot;\n    regex: &quot;^(?:\\\\w{1,256}:){0,10}[\\\\w.]{1,256}$$&quot;\n    string: &quot;insert your user id&quot;\n</li>\r\n        \r\n    </ul>\r\n\r\n<h2>Troubleshooting</h2>\r\n<ul>\r\n    <li>Verify that the content type of the request matches the service definition.</li>\r\n    <li>Check that the JSON document you are sending matches the schema.</li>\r\n    <li>If the service does not define any requests, make sure you are not sending a request body.</li>\r\n</ul>\r\n<footer><p>Error ID: 7001873889772119441</p><p>Dash Services Framework 62.3 [SVN build 8011 at 2021-01-22 16:07]</p></footer>\n</body>\n</html>\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<!--\nThe request did not match any of the requests defined for this endpoint.\nRequest definition 1: The JSON object in the body does not conform to the schema\nerror: ECMA 262 regex &quot;^(?:\\w{1,256}:){0,10}[\\w.]{1,256}$$&quot; does not match input string &quot;insert your user id&quot;\n    level: &quot;error&quot;\n    schema: {&quot;loadingURI&quot;:&quot;definition:/Token#&quot;,&quot;pointer&quot;:&quot;&quot;}\n    instance: {&quot;pointer&quot;:&quot;/entitlements/admin/0&quot;}\n    domain: &quot;validation&quot;\n    keyword: &quot;pattern&quot;\n    regex: &quot;^(?:\\\\w{1,256}:){0,10}[\\\\w.]{1,256}$$&quot;\n    string: &quot;insert your user id&quot;\n\n-->\n",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mMqRequestError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-8-8b4e83496b74>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[0mparameters\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mWorkspaceParameters\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlayout\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mlayout\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcomponents\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mcomponents\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdisclaimer\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdisclaimer\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[0mnew_workspace\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mWorkspace\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;34m'cashboard'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0malias\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0malias\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mentitlements\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mentitle\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdescription\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdescription\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mcreated_workspace\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mwk\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcreate_workspace\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnew_workspace\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      6\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mH:\\_repos\\gs_quant\\gs_quant\\api\\gs\\workspaces.py\u001b[0m in \u001b[0;36mcreate_workspace\u001b[1;34m(cls, workspace)\u001b[0m\n\u001b[0;32m     49\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     50\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mcreate_workspace\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mworkspace\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mWorkspace\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mWorkspace\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 51\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mGsSession\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurrent\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_post\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mf'{API}'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mworkspace\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcls\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mWorkspace\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrequest_headers\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mWORKSPACES_MARKETS_HEADERS\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     52\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     53\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0mclassmethod\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mH:\\_repos\\gs_quant\\gs_quant\\session.py\u001b[0m in \u001b[0;36m_post\u001b[1;34m(self, path, payload, request_headers, cls, include_version, timeout)\u001b[0m\n\u001b[0;32m    230\u001b[0m               include_version: bool = True, timeout: int = DEFAULT_TIMEOUT) -> Union[Base, tuple, dict]:\n\u001b[0;32m    231\u001b[0m         return self.__request('POST', path, payload=payload, request_headers=request_headers,\n\u001b[1;32m--> 232\u001b[1;33m                               cls=cls, include_version=include_version, timeout=timeout)\n\u001b[0m\u001b[0;32m    233\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    234\u001b[0m     def _delete(self, path: str, payload: Optional[Union[dict, Base]] = None, request_headers: Optional[dict]\n",
      "\u001b[1;32mH:\\_repos\\gs_quant\\gs_quant\\session.py\u001b[0m in \u001b[0;36m__request\u001b[1;34m(self, method, path, payload, request_headers, cls, try_auth, include_version, timeout)\u001b[0m\n\u001b[0;32m    195\u001b[0m             \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__request\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpath\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpayload\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mpayload\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcls\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mcls\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtry_auth\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    196\u001b[0m         \u001b[1;32melif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;36m199\u001b[0m \u001b[1;33m<\u001b[0m \u001b[0mresponse\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstatus_code\u001b[0m \u001b[1;33m<\u001b[0m \u001b[1;36m300\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 197\u001b[1;33m             \u001b[1;32mraise\u001b[0m \u001b[0mMqRequestError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mresponse\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstatus_code\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtext\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcontext\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'{} {}'\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmethod\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0murl\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    198\u001b[0m         \u001b[1;32melif\u001b[0m \u001b[1;34m'Content-Type'\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mresponse\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mheaders\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    199\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[1;34m'application/x-msgpack'\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mresponse\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mheaders\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'Content-Type'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mMqRequestError\u001b[0m: context: POST https://marquee.web.gs.com/v1/workspaces/markets\nstatus: 400, message: <!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\"/>\n<title>Request Body Validation Error</title>\n<style>body { font-family: sans-serif; } footer { font-style: italic; }</style>\n</head>\n<body>\n<h1>400 Bad Request - Request Body Validation Error</h1>\n\r\n<h2>Problem Description</h2>\r\n<p>\r\n    The request did not match any of the requests defined for this endpoint.\r\n</p>\r\n<h2>Details</h2>\r\n\r\n    <h3>Request Definition 1</h3>\r\n    <p>The JSON object in the body does not conform to the schema</p>\r\n    <ul>\r\n        \r\n        <li>error: ECMA 262 regex &quot;^(?:\\w{1,256}:){0,10}[\\w.]{1,256}$$&quot; does not match input string &quot;insert your user id&quot;\n    level: &quot;error&quot;\n    schema: {&quot;loadingURI&quot;:&quot;definition:/Token#&quot;,&quot;pointer&quot;:&quot;&quot;}\n    instance: {&quot;pointer&quot;:&quot;/entitlements/admin/0&quot;}\n    domain: &quot;validation&quot;\n    keyword: &quot;pattern&quot;\n    regex: &quot;^(?:\\\\w{1,256}:){0,10}[\\\\w.]{1,256}$$&quot;\n    string: &quot;insert your user id&quot;\n</li>\r\n        \r\n    </ul>\r\n\r\n<h2>Troubleshooting</h2>\r\n<ul>\r\n    <li>Verify that the content type of the request matches the service definition.</li>\r\n    <li>Check that the JSON document you are sending matches the schema.</li>\r\n    <li>If the service does not define any requests, make sure you are not sending a request body.</li>\r\n</ul>\r\n<footer><p>Error ID: 7001873889772119441</p><p>Dash Services Framework 62.3 [SVN build 8011 at 2021-01-22 16:07]</p></footer>\n</body>\n</html>\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n<!--\nThe request did not match any of the requests defined for this endpoint.\nRequest definition 1: The JSON object in the body does not conform to the schema\nerror: ECMA 262 regex &quot;^(?:\\w{1,256}:){0,10}[\\w.]{1,256}$$&quot; does not match input string &quot;insert your user id&quot;\n    level: &quot;error&quot;\n    schema: {&quot;loadingURI&quot;:&quot;definition:/Token#&quot;,&quot;pointer&quot;:&quot;&quot;}\n    instance: {&quot;pointer&quot;:&quot;/entitlements/admin/0&quot;}\n    domain: &quot;validation&quot;\n    keyword: &quot;pattern&quot;\n    regex: &quot;^(?:\\\\w{1,256}:){0,10}[\\\\w.]{1,256}$$&quot;\n    string: &quot;insert your user id&quot;\n\n-->\n"
     ]
    }
   ],
   "source": [
    "workspace.parameters.layout = 'r(c12($0))r(c6($1)c6($2))'\n",
    "workspace.parameters.components = components\n",
    "workspace = ws_api.update_workspace(workspace)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  },
  "pycharm": {
   "stem_cell": {
    "cell_type": "raw",
    "metadata": {
     "collapsed": false
    },
    "source": []
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}